package edu.mapi.ir.log;

import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Vector;

import javax.swing.JPanel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import edu.mapi.ir.viewer.MousePlayer;

/**
 * @author ZP
 */
public class LogReplay extends JPanel {
	private static DocumentBuilder db ;
	private String firstReply, labXML, gridXML;
	private BufferedReader reader;	
	private LinkedHashMap<String, LinkedHashMap<Integer, MousePlayer>> log = new LinkedHashMap<String, LinkedHashMap<Integer,MousePlayer>>();
	private int minTime = Integer.MAX_VALUE, maxTime = Integer.MIN_VALUE;
	private String filename = null;
	
	public Vector<MousePlayer> getStateAt(int time) {
		if (time < minTime || time > maxTime)
			return null;
		Vector<MousePlayer> state = new Vector<MousePlayer>();
		
		for (String s : log.keySet()) {
			MousePlayer mp = log.get(s).get(time);
			if (mp != null)
				state.add(mp);
		}
		
		return state;
	}
	
	private LogReplay(InputStream stream) {
		try {
			db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			reader = new BufferedReader(new InputStreamReader(stream));
			firstReply = nextMessage();
			labXML = nextMessage();
			gridXML = nextMessage();
			
			String message = nextMessage();
			
			while (message != null) {
				MousePlayer mp = parseRobotMessage(message);
				if (mp == null) {
					message = nextMessage();
					continue;
				}
				String uid = mp.getPlayerName()+mp.getId();
				if (!log.containsKey(uid)) {
					log.put(uid, new LinkedHashMap<Integer, MousePlayer>());
				}
				log.get(uid).put(mp.getTime(), mp);
				maxTime = Math.max(maxTime, mp.getTime());
				minTime = Math.min(minTime, mp.getTime());
				message = nextMessage();
			}			
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private String nextMessage() {
		String msg = "";
		
		try {
			
			String line = reader.readLine();
			while (line != null) {				
				if (line.equalsIgnoreCase("<sync/>")) {					
					return msg;
				}
				else {					
					msg = msg + "\n"+line;
				}
				line = reader.readLine();
			}
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}				
	}
	
	private LogReplay(String filename) throws FileNotFoundException {
		this(new FileInputStream(filename));
		this.filename = filename;
	}
	
	public static LogReplay parseLog(String logFile) {
		try {
			LogReplay replay = new LogReplay(logFile);
			return replay;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}	
	}
	
	public static LogReplay parseLog(InputStream stream) {
		try {
			LogReplay replay = new LogReplay(stream);
			return replay;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}	
	}
	
	public static MousePlayer parseRobotMessage(String robotMessage) {
		try {
			Document doc = db.parse(new ByteArrayInputStream(robotMessage.getBytes()));
			Node root = doc.getChildNodes().item(0);
			
			if (root.getNodeName().equals("Robot")) {
				
				NamedNodeMap posAttrs =root.getChildNodes().item(1).getAttributes();
				int id = Integer.parseInt(root.getAttributes().getNamedItem("Id").getTextContent());
				double x = Double.parseDouble(posAttrs.getNamedItem("X").getTextContent());
				double y = Double.parseDouble(posAttrs.getNamedItem("Y").getTextContent());
				double dir = Double.parseDouble(posAttrs.getNamedItem("Dir").getTextContent());
				
				MousePlayer mp = new MousePlayer(new Point2D.Double(x,y));
				mp.setDirection(dir);
				//mp.getPosition().setLocation(x, y);				
				mp.setPlayerName(root.getAttributes().getNamedItem("Name").getTextContent());
				mp.setId(id);
				mp.setTime(Integer.parseInt(root.getAttributes().getNamedItem("Time").getTextContent()));
				mp.setScore(Integer.parseInt(root.getAttributes().getNamedItem("Score").getTextContent()));
				mp.setArrivalTime(Integer.parseInt(root.getAttributes().getNamedItem("ArrivalTime").getTextContent()));
				mp.setCollisions(Integer.parseInt(root.getAttributes().getNamedItem("Collisions").getTextContent()));
				mp.setReturningTime(Integer.parseInt(root.getAttributes().getNamedItem("ReturningTime").getTextContent()));
				mp.setColision(root.getAttributes().getNamedItem("Collision").getTextContent().equals("True")? true : false);
				mp.setVisitedMask(Integer.parseInt(root.getAttributes().getNamedItem("VisitedMask").getTextContent()));
				mp.setState(root.getAttributes().getNamedItem("State").getTextContent());
				
				return mp;
			}			
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public static void main(String[] args) {
		LogReplay lr = LogReplay.parseLog("C:/Programas/Eclipse/workspace/MazeViewer/logs/2008-05-31_16-01-50.log");
		
		System.out.println(lr.getStateAt(0));
	}

	public String getFirstReply() {
		return firstReply;
	}

	public String getLabXML() {
		return labXML;
	}

	public String getGridXML() {
		return gridXML;
	}

	public int getMinTime() {
		return minTime;
	}

	public int getMaxTime() {
		return maxTime;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}
	
}
